package cn.thornbird.orgsync.util;

import lombok.extern.slf4j.Slf4j;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.Calendar;
import java.util.Date;

@Slf4j
public class DateUtil {

    public static final String DATE_FORMAT = "yyyy-MM-dd";

    public static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

    public static final String PURE_DATE_FORMAT = "yyyyMMdd";

    public static Date addDays(Date date, int days) {
        Calendar calendar = Calendar.getInstance();
        calendar.setLenient(false);
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, days);
        return calendar.getTime();
    }

    public static Date addMonths(Date date, int months) {
        Calendar calendar = Calendar.getInstance();
        calendar.setLenient(false);
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, months);
        return calendar.getTime();
    }

    public static Date addYears(Date date, int years) {
        Calendar calendar = Calendar.getInstance();
        calendar.setLenient(false);
        calendar.setTime(date);
        calendar.add(Calendar.YEAR, years);
        return calendar.getTime();
    }

    public static Date createDate(Date date) {
        if (date == null) {
            date = new Date();
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
        return createDate(year, month, dayOfMonth, 0, 0, 0);
    }

    public static Date createDate(int year, int month, int dayOfMonth) {
        return createDate(year, month, dayOfMonth, 0, 0, 0);
    }

    public static Date createDate(int year, int month, int dayOfMonth, int hourOfDay, int minute, int second) {
        return createDate(year, month, dayOfMonth, hourOfDay, minute, second, 0);
    }

    public static Date createDate(int year, int month, int dayOfMonth, int hourOfDay, int minute, int second,
                                  int millisecond) {
        Calendar calendar = Calendar.getInstance();
        calendar.setLenient(false);
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month);
        calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        calendar.set(Calendar.MILLISECOND, millisecond);
        return calendar.getTime();
    }

    public static Date getDateWithTime(Date date, int hourOfDay, int minute, int second, int millisecond) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        if (hourOfDay >= 0) {
            calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
        }
        if (minute >= 0) {
            calendar.set(Calendar.MINUTE, minute);
        }
        if (second >= 0) {
            calendar.set(Calendar.SECOND, second);
        }
        if (millisecond >= 0) {
            calendar.set(Calendar.MILLISECOND, millisecond);
        }
        return calendar.getTime();
    }

    public static int getDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.DAY_OF_MONTH);
    }

    public static int getDayOfWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.setFirstDayOfWeek(Calendar.SUNDAY);
        return calendar.get(Calendar.DAY_OF_WEEK) - 1;
    }

    public static Date getFirstDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTime();
    }

    public static Date getLastDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return addDays(getFirstDayOfMonth(addMonths(calendar.getTime(), 1)), -1);
    }

    public static Date getYesterday(Date date) {
        date = createDate(date);
        return addDays(date, -1);
    }

    public static boolean isSameDay(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return false;
        }
        return createDate(date1).equals(createDate(date2));
    }

    public static long daysBetween(Date date1, Date date2) {
        return Duration.between(date1.toInstant(), date2.toInstant()).toDays();
    }

    public static long hoursBetween(Date date1, Date date2) {
        return Duration.between(date1.toInstant(), date2.toInstant()).toHours();
    }

    public static long minutesBetween(Date date1, Date date2) {
        return Duration.between(date1.toInstant(), date2.toInstant()).toMinutes();
    }

    public static long secondsBetween(Date date1, Date date2) {
        return Duration.between(date1.toInstant(), date2.toInstant()).getSeconds();
    }

    public static String formatDate(Date date, String format) {
        String text = "";
        if (date == null) {
            return text;
        }

        DateFormat dateFormat = new SimpleDateFormat(format);
        text = dateFormat.format(date);
        return text;
    }

    public static Date parseDate(String dateText, String format) {
        Date date = null;
        dateText = dateText == null ? "" : dateText.trim();
        if (dateText.isEmpty()) {
            return date;
        }

        DateFormat dateFormat = new SimpleDateFormat(format);
        try {
            date = dateFormat.parse(dateText);
        } catch (ParseException e) {
            log.error("error", e);
        }
        return date;
    }

    public static Date setTime(Date date, int hourOfDay, int minute, int second) {
        return setTime(date, hourOfDay, minute, second, 0);
    }

    public static Date setTime(Date date, int hourOfDay, int minute, int second, int millisecond) {
        Calendar calendar = Calendar.getInstance();
        calendar.setLenient(false);
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        calendar.set(Calendar.MILLISECOND, millisecond);
        return calendar.getTime();
    }

}
